home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmcd-1.4 / libdi.d / os_cdsim.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  18.6 KB  |  960 lines

  1. /*
  2.  *   libdi - CD Audio Player Device Interface Library
  3.  *
  4.  *   Copyright (C) 1995  Ti Kan
  5.  *   E-mail: ti@amb.org
  6.  *
  7.  *   This program is free software; you can redistribute it and/or modify
  8.  *   it under the terms of the GNU General Public License as published by
  9.  *   the Free Software Foundation; either version 2 of the License, or
  10.  *   (at your option) any later version.
  11.  *
  12.  *   This program is distributed in the hope that it will be useful,
  13.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *   GNU General Public License for more details.
  16.  *
  17.  *   You should have received a copy of the GNU General Public License
  18.  *   along with this program; if not, write to the Free Software
  19.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  */
  22. #ifndef LINT
  23. static char *_os_cdsim_c_ident_ = "@(#)os_cdsim.c    5.3 94/12/28";
  24. #endif
  25.  
  26. #include "common.d/appenv.h"
  27. #include "common.d/util.h"
  28. #include "libdi.d/libdi.h"
  29. #include "libdi.d/scsipt.h"
  30.  
  31.  
  32. #ifdef DEMO_ONLY
  33.  
  34. #ifndef CDSIM_VERS
  35. #define CDSIM_VERS        "1.01"    /* CD-ROM simulator version */
  36. #endif
  37.  
  38. extern appdata_t        app_data;
  39. extern int            cdsim_sfd[],
  40.                 cdsim_rfd[];
  41. extern FILE            *errfp;
  42.  
  43. STATIC simstat_t        cdsim_stat;
  44. STATIC time_t            cdsim_start_time = 0,
  45.                 cdsim_pause_time = 0,
  46.                 cdsim_pause_elapsed = 0,
  47.                 cdsim_prev_pause = 0,
  48.                 cdsim_elapsed = 0,
  49.                 cdsim_now;
  50.  
  51. STATIC inquiry_data_t        cdsim_inqdata;
  52. STATIC byte_t            cdsim_tocdata1[SZ_RDTOC],
  53.                 cdsim_tocdata2[SZ_RDTOC];
  54.  
  55.  
  56.  
  57. /*
  58.  * cdsim_sendpkt
  59.  *    Write a CD simulator packet down the pipe
  60.  *
  61.  * Args:
  62.  *    name - The text string describing the caller module
  63.  *    fd - Pipe file descriptor
  64.  *    s - Pointer to the packet data
  65.  *
  66.  * Return:
  67.  *    TRUE - pipe write successful
  68.  *    FALSE - pipe write failed
  69.  */
  70. bool_t
  71. cdsim_sendpkt(char *name, int fd, simpkt_t *s)
  72. {
  73.     byte_t    *p = (byte_t *) s;
  74.     int    i,
  75.         ret;
  76.  
  77.     if (fd < 0)
  78.         return FALSE;
  79.  
  80.     /* Brand packet with magic number */
  81.     s->magic = CDSIM_MAGIC;
  82.  
  83.     /* Send a packet */
  84.     i = CDSIM_PKTSZ;
  85.     while ((ret = write(fd, p, i)) < i) {
  86.         if (ret < 0 && errno != EBADF) {
  87.             fprintf(errfp, "%s: packet write error (errno=%d)\n",
  88.                 name, errno);
  89.             return FALSE;
  90.         }
  91.  
  92.         if (ret == 0) {
  93.             /* avoid hogging CPU */
  94.             sleep(1);
  95.         }
  96.         else {
  97.             i -= ret;
  98.             p += ret;
  99.         }
  100.     }
  101.  
  102.     return TRUE;
  103. }
  104.  
  105.  
  106. /*
  107.  * cdsim_getpkt
  108.  *    Read a CD simulator packet from the pipe
  109.  *
  110.  * Args:
  111.  *    name - The text string describing the caller module
  112.  *    fd - Pipe file descriptor
  113.  *    s - Pointer to the packet data
  114.  *
  115.  * Return:
  116.  *    TRUE - pipe read successful
  117.  *    FALSE - pipe read failed
  118.  */
  119. bool_t
  120. cdsim_getpkt(char *name, int fd, simpkt_t *r)
  121. {
  122.     byte_t    *p = (byte_t *) r;
  123.     int    i,
  124.         ret;
  125.  
  126.     if (fd < 0)
  127.         return FALSE;
  128.  
  129.     /* Get a packet */
  130.     i = CDSIM_PKTSZ;
  131.     while ((ret = read(fd, p, i)) < i) {
  132.         if (ret < 0 && errno != EBADF) {
  133.             fprintf(errfp, "%s: packet read error (errno=%d)\n",
  134.                 name, errno);
  135.             return FALSE;
  136.         }
  137.  
  138.         if (ret == 0) {
  139.             /* avoid hogging CPU */
  140.             sleep(1);
  141.         }
  142.         else {
  143.             i -= ret;
  144.             p += ret;
  145.         }
  146.     }
  147.  
  148.     /* Check packet for magic number */
  149.     if (r->magic != CDSIM_MAGIC) {
  150.         fprintf(errfp, "%s: bad packet magic number.\n", name);
  151.         return FALSE;
  152.     }
  153.  
  154.     return TRUE;
  155. }
  156.  
  157.  
  158. /*
  159.  * cdsim_sig
  160.  *    CD simulator process signal handler
  161.  *
  162.  * Args:
  163.  *    sig - The signal number
  164.  *
  165.  * Return:
  166.  *    Nothing.
  167.  */
  168. /*ARGSUSED*/
  169. STATIC void
  170. cdsim_sig(int sig)
  171. {
  172.     fprintf(errfp, "CD-ROM simulator exiting.\n");
  173.     exit(0);
  174. }
  175.  
  176.  
  177. /*
  178.  * cdsim_s_test
  179.  *    Test Unit Ready command simulation function
  180.  *
  181.  * Args:
  182.  *    r - Pointer to the command packet
  183.  *    s - Pointer to the response packet
  184.  *
  185.  * Return:
  186.  *    Command completion status code
  187.  */
  188. /*ARGSUSED*/
  189. STATIC word32_t
  190. cdsim_s_test(simpkt_t *r, simpkt_t *s)
  191. {
  192.     if (cdsim_stat.status == CDSIM_NODISC)
  193.         return CDSIM_COMPERR;
  194.     else
  195.         return CDSIM_COMPOK;
  196. }
  197.  
  198.  
  199. /*
  200.  * cdsim_s_inquir
  201.  *    Inquiry command simulation function
  202.  *
  203.  * Args:
  204.  *    r - Pointer to the command packet
  205.  *    s - Pointer to the response packet
  206.  *
  207.  * Return:
  208.  *    Command completion status code
  209.  */
  210. STATIC byte_t
  211. cdsim_s_inquir(simpkt_t *r, simpkt_t *s)
  212. {
  213.     s->len = (r->len > CDSIM_INQSZ) ? CDSIM_INQSZ : r->len;
  214.  
  215.     /* Copy inquiry data into packet */
  216.     memcpy(s->data, (byte_t *) &cdsim_inqdata, s->len);
  217.  
  218.     return CDSIM_COMPOK;
  219. }
  220.  
  221.  
  222. /*
  223.  * cdsim_s_mselect
  224.  *    Mode Select command simulation function
  225.  *
  226.  * Args:
  227.  *    r - Pointer to the command packet
  228.  *    s - Pointer to the response packet
  229.  *
  230.  * Return:
  231.  *    Command completion status code
  232.  */
  233. /*ARGSUSED*/
  234. STATIC byte_t
  235. cdsim_s_mselect(simpkt_t *r, simpkt_t *s)
  236. {
  237.     return CDSIM_COMPOK;
  238. }
  239.  
  240.  
  241. /*
  242.  * cdsim_s_msense
  243.  *    Mode Sense command simulation function
  244.  *
  245.  * Args:
  246.  *    r - Pointer to the command packet
  247.  *    s - Pointer to the response packet
  248.  *
  249.  * Return:
  250.  *    Command completion status code
  251.  */
  252. /*ARGSUSED*/
  253. STATIC byte_t
  254. cdsim_s_msense(simpkt_t *r, simpkt_t *s)
  255. {
  256.     return CDSIM_COMPOK;
  257. }
  258.  
  259.  
  260. /*
  261.  * cdsim_s_start
  262.  *    Start/Stop Unit command simulation function
  263.  *
  264.  * Args:
  265.  *    r - Pointer to the command packet
  266.  *    s - Pointer to the response packet
  267.  *
  268.  * Return:
  269.  *    Command completion status code
  270.  */
  271. /*ARGSUSED*/
  272. STATIC byte_t
  273. cdsim_s_start(simpkt_t *r, simpkt_t *s)
  274. {
  275.     cdsim_start_time = 0;
  276.     cdsim_elapsed = 0;
  277.     cdsim_pause_time = 0;
  278.     cdsim_pause_elapsed = 0;
  279.     cdsim_prev_pause = 0;
  280.  
  281.     if (r->cdb[4] & 0x01) {
  282.         /* Start unit */
  283.         if (r->cdb[4] & 0x02) {
  284.             /* Load disc */
  285.             cdsim_stat.status = CDSIM_STOPPED;
  286.             return CDSIM_COMPOK;
  287.         }
  288.         else if (cdsim_stat.status == CDSIM_NODISC)
  289.             return CDSIM_COMPERR;
  290.     }
  291.     else {
  292.         /* Stop unit */
  293.         if (cdsim_stat.status == CDSIM_NODISC)
  294.             return CDSIM_COMPERR;
  295.         else if (r->cdb[4] & 0x02) {
  296.             /* Eject disc */
  297.             if (cdsim_stat.caddylock)
  298.                 return CDSIM_COMPERR;
  299.             else {
  300.                 cdsim_stat.status = CDSIM_NODISC;
  301.                 return CDSIM_COMPOK;
  302.             }
  303.         }
  304.         else {
  305.             /* Stop disc */
  306.             cdsim_stat.status = CDSIM_STOPPED;
  307.             return CDSIM_COMPOK;
  308.         }
  309.     }
  310.     return CDSIM_COMPOK;
  311. }
  312.  
  313.  
  314. /*
  315.  * cdsim_s_prevent
  316.  *    Prevent/Allow Medium Removal command simulation function
  317.  *
  318.  * Args:
  319.  *    r - Pointer to the command packet
  320.  *    s - Pointer to the response packet
  321.  *
  322.  * Return:
  323.  *    Command completion status code
  324.  */
  325. /*ARGSUSED*/
  326. STATIC byte_t
  327. cdsim_s_prevent(simpkt_t *r, simpkt_t *s)
  328. {
  329.     if (r->cdb[4] & 0x01)
  330.         cdsim_stat.caddylock = TRUE;
  331.     else
  332.         cdsim_stat.caddylock = FALSE;
  333.  
  334.     return CDSIM_COMPOK;
  335. }
  336.  
  337.  
  338. /*
  339.  * cdsim_m_rdsubq
  340.  *    Read Subchannel command simulation function
  341.  *
  342.  * Args:
  343.  *    r - Pointer to the command packet
  344.  *    s - Pointer to the response packet
  345.  *
  346.  * Return:
  347.  *    Command completion status code
  348.  */
  349. STATIC byte_t
  350. cdsim_m_rdsubq(simpkt_t *r, simpkt_t *s)
  351. {
  352.     subq_hdr_t    *h = (subq_hdr_t *)(void *) s->data;
  353.     subq_01_t    *s1 = (subq_01_t *)(void *)
  354.                   (s->data + sizeof(subq_hdr_t));
  355.  
  356.     /* Subchannel formats */
  357.     switch (r->cdb[3]) {
  358.     case SUB_CURPOS:
  359.         h->subch_len = 15;
  360.  
  361.         s1->fmt_code = SUB_CURPOS;
  362.         s1->preemph = 0;
  363.         s1->copyallow = 0;
  364.         s1->trktype = 0;
  365.         s1->audioch = 0;
  366.         s1->adr = 0;
  367.  
  368.         s1->trkno = cdsim_stat.trkno;
  369.         s1->idxno = cdsim_stat.idxno;
  370.  
  371.         if (r->cdb[1] & 0x02) {
  372.             blktomsf(
  373.                 cdsim_stat.absaddr,
  374.                 &s1->abs_addr.msf.min,
  375.                 &s1->abs_addr.msf.sec,
  376.                 &s1->abs_addr.msf.frame,
  377.                 FRAME_PER_SEC << 1
  378.             );
  379.  
  380.             blktomsf(
  381.                 cdsim_stat.reladdr,
  382.                 &s1->rel_addr.msf.min,
  383.                 &s1->rel_addr.msf.sec,
  384.                 &s1->rel_addr.msf.frame,
  385.                 0
  386.             );
  387.         }
  388.         else {
  389.             s1->abs_addr.logical = bswap32(cdsim_stat.absaddr);
  390.             s1->rel_addr.logical = bswap32(cdsim_stat.reladdr);
  391.         }
  392.  
  393.         s->len = sizeof(subq_hdr_t) + sizeof(subq_01_t);
  394.  
  395.         break;
  396.  
  397.     default:
  398.         /* The other formats are not implemented */
  399.         return CDSIM_COMPERR;
  400.     }
  401.  
  402.     switch (cdsim_stat.status) {
  403.     case CDSIM_PLAYING:
  404.         h->audio_status = AUDIO_PLAYING;
  405.         break;
  406.  
  407.     case CDSIM_PAUSED:
  408.         h->audio_status = AUDIO_PAUSED;
  409.         break;
  410.  
  411.     default:
  412.         h->audio_status = AUDIO_COMPLETED;
  413.         break;
  414.     }
  415.  
  416.     return CDSIM_COMPOK;
  417. }
  418.  
  419.  
  420. /*
  421.  * cdsim_m_rdtoc
  422.  *    Read TOC command simulation function
  423.  *
  424.  * Args:
  425.  *    r - Pointer to the command packet
  426.  *    s - Pointer to the response packet
  427.  *
  428.  * Return:
  429.  *    Command completion status code
  430.  */
  431. STATIC byte_t
  432. cdsim_m_rdtoc(simpkt_t *r, simpkt_t *s)
  433. {
  434.     byte_t    *startoff;
  435.  
  436.     if (r->cdb[1] & 0x02)
  437.         startoff = cdsim_tocdata2 + sizeof(toc_hdr_t);
  438.     else
  439.         startoff = cdsim_tocdata1 + sizeof(toc_hdr_t);
  440.  
  441.     s->len = (r->len > SZ_RDTOC) ? SZ_RDTOC : r->len;
  442.  
  443.     if (r->cdb[6] > 1) {
  444.         int    skip;
  445.  
  446.         skip = ((int) r->cdb[6] - 1) *
  447.             sizeof(toc_trk_descr_t);
  448.         s->len -= skip;
  449.         startoff += skip;
  450.     }
  451.  
  452.     /* Copy TOC data into packet */
  453.  
  454.     /* Header info */
  455.     memcpy(s->data, cdsim_tocdata1, sizeof(toc_hdr_t));
  456.  
  457.     /* TOC data */
  458.     memcpy(s->data + sizeof(toc_hdr_t), startoff, s->len);
  459.  
  460.     return CDSIM_COMPOK;
  461. }
  462.  
  463.  
  464. /*
  465.  * cdsim_m_play
  466.  *    Play Audio (10) command simulation function
  467.  *
  468.  * Args:
  469.  *    r - Pointer to the command packet
  470.  *    s - Pointer to the response packet
  471.  *
  472.  * Return:
  473.  *    Command completion status code
  474.  */
  475. /*ARGSUSED*/
  476. STATIC byte_t
  477. cdsim_m_play(simpkt_t *r, simpkt_t *s)
  478. {
  479.     cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
  480.         (r->cdb[4] << 8) | r->cdb[5];
  481.     cdsim_stat.endaddr = cdsim_stat.startaddr +
  482.         ((r->cdb[7] << 8) | r->cdb[8]);
  483.  
  484.     if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
  485.         return CDSIM_PARMERR;
  486.  
  487.     cdsim_start_time = cdsim_now;
  488.     cdsim_elapsed = 0;
  489.     cdsim_pause_time = 0;
  490.     cdsim_pause_elapsed = 0;
  491.     cdsim_prev_pause = 0;
  492.  
  493.     cdsim_stat.status = CDSIM_PLAYING;
  494.  
  495.     return CDSIM_COMPOK;
  496. }
  497.  
  498.  
  499. /*
  500.  * cdsim_m_playmsf
  501.  *    Play Audio MSF command simulation function
  502.  *
  503.  * Args:
  504.  *    r - Pointer to the command packet
  505.  *    s - Pointer to the response packet
  506.  *
  507.  * Return:
  508.  *    Command completion status code
  509.  */
  510. /*ARGSUSED*/
  511. STATIC byte_t
  512. cdsim_m_playmsf(simpkt_t *r, simpkt_t *s)
  513. {
  514.     msftoblk(r->cdb[3], r->cdb[4], r->cdb[5], &cdsim_stat.startaddr,
  515.          FRAME_PER_SEC << 1);
  516.     msftoblk(r->cdb[6], r->cdb[7], r->cdb[8], &cdsim_stat.endaddr,
  517.          FRAME_PER_SEC << 1);
  518.  
  519.     if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
  520.         return CDSIM_PARMERR;
  521.  
  522.     cdsim_start_time = cdsim_now;
  523.     cdsim_elapsed = 0;
  524.     cdsim_pause_time = 0;
  525.     cdsim_pause_elapsed = 0;
  526.     cdsim_prev_pause = 0;
  527.  
  528.     cdsim_stat.status = CDSIM_PLAYING;
  529.  
  530.     return CDSIM_COMPOK;
  531. }
  532.  
  533.  
  534. /*
  535.  * cdsim_m_playti
  536.  *    Play Audio Track/index command simulation function
  537.  *
  538.  * Args:
  539.  *    r - Pointer to the command packet
  540.  *    s - Pointer to the response packet
  541.  *
  542.  * Return:
  543.  *    Command completion status code
  544.  */
  545. /*ARGSUSED*/
  546. STATIC byte_t
  547. cdsim_m_playti(simpkt_t *r, simpkt_t *s)
  548. {
  549.     int    strk = (int) r->cdb[4],
  550.         sidx = (int) r->cdb[5],
  551.         etrk = (int) r->cdb[7],
  552.         eidx = (int) r->cdb[8];
  553.  
  554.     if (sidx > (int) cdsim_stat.trk[strk - 1].nidxs) {
  555.         strk++;
  556.         sidx = 1;
  557.     }
  558.  
  559.     if (strk > (int) cdsim_stat.ntrks || etrk > (int) cdsim_stat.ntrks)
  560.         return CDSIM_PARMERR;
  561.  
  562.     if (eidx > (int) cdsim_stat.trk[strk - 1].nidxs)
  563.         eidx = (int) cdsim_stat.trk[strk - 1].nidxs;
  564.  
  565.     cdsim_stat.startaddr = cdsim_stat.trk[strk - 1].iaddr[sidx - 1];
  566.     cdsim_stat.endaddr = cdsim_stat.trk[etrk].iaddr[eidx - 1];
  567.  
  568.     if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
  569.         return CDSIM_PARMERR;
  570.  
  571.     cdsim_start_time = cdsim_now;
  572.     cdsim_elapsed = 0;
  573.     cdsim_pause_time = 0;
  574.     cdsim_pause_elapsed = 0;
  575.     cdsim_prev_pause = 0;
  576.  
  577.     cdsim_stat.status = CDSIM_PLAYING;
  578.  
  579.     return CDSIM_COMPOK;
  580. }
  581.  
  582.  
  583. /*
  584.  * cdsim_m_pause
  585.  *    Pause/Resume command simulation function
  586.  *
  587.  * Args:
  588.  *    r - Pointer to the command packet
  589.  *    s - Pointer to the response packet
  590.  *
  591.  * Return:
  592.  *    Command completion status code
  593.  */
  594. /*ARGSUSED*/
  595. STATIC byte_t
  596. cdsim_m_pause(simpkt_t *r, simpkt_t *s)
  597. {
  598.     if (cdsim_stat.status == CDSIM_PAUSED && r->cdb[8] & 0x01) {
  599.         /* Resume */
  600.         cdsim_stat.status = CDSIM_PLAYING;
  601.         cdsim_prev_pause += cdsim_pause_elapsed;
  602.         cdsim_pause_elapsed = 0;
  603.  
  604.         return CDSIM_COMPOK;
  605.     }
  606.     else {
  607.         cdsim_stat.status = CDSIM_PAUSED;
  608.         time(&cdsim_pause_time);
  609.         return CDSIM_COMPOK;
  610.     }
  611. }
  612.  
  613.  
  614. /*
  615.  * cdsim_m_pause
  616.  *    Play Audio (12) command simulation function
  617.  *
  618.  * Args:
  619.  *    r - Pointer to the command packet
  620.  *    s - Pointer to the response packet
  621.  *
  622.  * Return:
  623.  *    Command completion status code
  624.  */
  625. /*ARGSUSED*/
  626. STATIC byte_t
  627. cdsim_l_play(simpkt_t *r, simpkt_t *s)
  628. {
  629.     cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
  630.         (r->cdb[4] << 8) | r->cdb[5];
  631.     cdsim_stat.endaddr = cdsim_stat.startaddr +
  632.         ((r->cdb[6] << 24) | (r->cdb[7] << 16) |
  633.          (r->cdb[8] << 8) | r->cdb[9]);
  634.  
  635.     if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
  636.         return CDSIM_PARMERR;
  637.  
  638.     cdsim_start_time = cdsim_now;
  639.     cdsim_elapsed = 0;
  640.     cdsim_pause_time = 0;
  641.     cdsim_pause_elapsed = 0;
  642.     cdsim_prev_pause = 0;
  643.  
  644.     cdsim_stat.status = CDSIM_PLAYING;
  645.  
  646.     return CDSIM_COMPOK;
  647. }
  648.  
  649.  
  650. /*
  651.  * cdsim_svccmd
  652.  *    Service a command
  653.  *
  654.  * Args:
  655.  *    r - Pointer to the command packet
  656.  *    s - Pointer to the response packet
  657.  *
  658.  * Return:
  659.  *    TRUE - success
  660.  *    FALSE - failure
  661.  */
  662. STATIC bool_t
  663. cdsim_svccmd(simpkt_t *r, simpkt_t *s)
  664. {
  665.     memset(s, 0, CDSIM_PKTSZ);
  666.  
  667.     DBGPRN(errfp, "\ncdsim: pktid=%d cdbsz=%d len=%d dir=%d cdb=",
  668.         r->pktid, r->cdbsz, r->len, r->dir);
  669.  
  670.     DBGDUMP("cdsim: SCSI CDB bytes", (byte_t *) r->cdb, (int) r->cdbsz);
  671.  
  672.     /* Set return packet id */
  673.     s->pktid = r->pktid;
  674.  
  675.     /* Copy CDB */
  676.     s->cdbsz = r->cdbsz;
  677.     memcpy(s->cdb, r->cdb, r->cdbsz);
  678.  
  679.     /* Truncate if necessary */
  680.     if (s->len > MAX_DATALEN)
  681.         s->len = MAX_DATALEN;
  682.  
  683.     /* Direction flag */
  684.     s->dir = r->dir;
  685.  
  686.     /* Interpret CDB and service the command */
  687.     switch (r->cdb[0]) {
  688.     case OP_S_TEST:
  689.         /* Test unit ready */
  690.         s->retcode = cdsim_s_test(r, s);
  691.         break;
  692.  
  693.     case OP_S_INQUIR:
  694.         /* Inquiry */
  695.         s->retcode = cdsim_s_inquir(r, s);
  696.         break;
  697.  
  698.     case OP_S_MSELECT:
  699.         /* Mode select */
  700.         s->retcode = cdsim_s_mselect(r, s);
  701.         break;
  702.  
  703.     case OP_S_MSENSE:
  704.         /* Mode sense */
  705.         s->retcode = cdsim_s_msense(r, s);
  706.         break;
  707.  
  708.     case OP_S_START:
  709.         /* Start/stop unit */
  710.         s->retcode = cdsim_s_start(r, s);
  711.         break;
  712.  
  713.     case OP_S_PREVENT:
  714.         /* Prevent/allow medium removal */
  715.         s->retcode = cdsim_s_prevent(r, s);
  716.         break;
  717.  
  718.     case OP_M_RDSUBQ:
  719.         /* Read subchannel */
  720.         s->retcode = cdsim_m_rdsubq(r, s);
  721.         break;
  722.  
  723.     case OP_M_RDTOC:
  724.         /* Read TOC */
  725.         s->retcode = cdsim_m_rdtoc(r, s);
  726.         break;
  727.  
  728.     case OP_M_PLAY:
  729.         /* Play audio (10) */
  730.         s->retcode = cdsim_m_play(r, s);
  731.         break;
  732.  
  733.     case OP_M_PLAYMSF:
  734.         /* Play audio MSF */
  735.         s->retcode = cdsim_m_playmsf(r, s);
  736.         break;
  737.  
  738.     case OP_M_PLAYTI:
  739.         /* Play audio track/index */
  740.         s->retcode = cdsim_m_playti(r, s);
  741.         break;
  742.  
  743.     case OP_M_PAUSE:
  744.         /* Pause/resume */
  745.         s->retcode = cdsim_m_pause(r, s);
  746.         break;
  747.  
  748.     case OP_L_PLAY:
  749.         /* Play audio (12) */
  750.         s->retcode = cdsim_l_play(r, s);
  751.         break;
  752.  
  753.     default:
  754.         /* Command not implemented */
  755.         s->retcode = CDSIM_NOTSUPP;
  756.         break;
  757.     }
  758.  
  759.     return (cdsim_sendpkt("cdsim", cdsim_rfd[1], s));
  760. }
  761.  
  762.  
  763. /*
  764.  * cdsim_init
  765.  *    Initialize the CD-simulator subsystem
  766.  *
  767.  * Args:
  768.  *    Nothing.
  769.  *
  770.  * Return:
  771.  *    Nothing.
  772.  */
  773. STATIC void
  774. cdsim_init(void)
  775. {
  776.     int        i,
  777.             j;
  778.     toc_hdr_t    *h1 = (toc_hdr_t *)(void *) cdsim_tocdata1,
  779.             *h2 = (toc_hdr_t *)(void *) cdsim_tocdata2;
  780.     toc_trk_descr_t    *t1,
  781.             *t2;
  782.  
  783.     /* Initialize internal states */
  784.     cdsim_stat.status = CDSIM_STOPPED;
  785.     cdsim_stat.ntrks = CDSIM_NTRKS;
  786.     cdsim_stat.absaddr = 0;
  787.     cdsim_stat.reladdr = 0;
  788.     cdsim_stat.startaddr = 0;
  789.     cdsim_stat.endaddr = 0;
  790.     cdsim_stat.caddylock = 0;
  791.  
  792.     /* Addresses for each simulated track and index */
  793.     for (i = 0; i < CDSIM_NTRKS; i++) {
  794.         if (i == 0)
  795.             cdsim_stat.trk[i].addr = 0;
  796.         else
  797.             cdsim_stat.trk[i].addr = (i * CDSIM_TRKLEN) - 150;
  798.  
  799.         cdsim_stat.trk[i].nidxs = CDSIM_NIDXS;
  800.  
  801.         for (j = 0; j < (int) cdsim_stat.trk[i].nidxs; j++) {
  802.             cdsim_stat.trk[i].iaddr[j] = (j * CDSIM_IDXLEN) +
  803.                              cdsim_stat.trk[i].addr;
  804.         }
  805.     }
  806.  
  807.     /* Simulated lead-out track */
  808.     cdsim_stat.trk[i].addr = (i * CDSIM_TRKLEN) - 150;
  809.     cdsim_stat.trk[i].nidxs = 0;
  810.     for (j = 0; j < CDSIM_NIDXS; j++)
  811.         cdsim_stat.trk[i].iaddr[j] = cdsim_stat.trk[i].addr;
  812.  
  813.     /* Initialize inquiry data */
  814.     cdsim_inqdata.type = DEV_ROM;
  815.     cdsim_inqdata.pqual = 0;
  816.     cdsim_inqdata.qualif = 0;
  817.     cdsim_inqdata.rmb = 1;
  818.     cdsim_inqdata.ver = 2;
  819.     cdsim_inqdata.len = 38;
  820.     strncpy((char *) cdsim_inqdata.vendor, "XMCD    ", 8);
  821.     strncpy((char *) cdsim_inqdata.prod, "CD-ROM SIMULATOR", 16);
  822.     strncpy((char *) cdsim_inqdata.revnum, CDSIM_VERS, 4);
  823.  
  824.     /* Initialize TOC data */
  825.     h1->data_len = h2->data_len = bswap16(
  826.         ((CDSIM_NTRKS + 1) * sizeof(toc_trk_descr_t)) + 2
  827.     );
  828.  
  829.     h1->first_trk = h2->first_trk = 1;
  830.     h1->last_trk = h2->last_trk = CDSIM_NTRKS;
  831.  
  832.     t1 = (toc_trk_descr_t *)(void *) (cdsim_tocdata1 + sizeof(toc_hdr_t));
  833.     t2 = (toc_trk_descr_t *)(void *) (cdsim_tocdata2 + sizeof(toc_hdr_t));
  834.  
  835.     for (i = 0; i < CDSIM_NTRKS; i++) {
  836.         t1->preemph = t2->preemph = 0;
  837.         t1->copyallow = t2->copyallow = 0;
  838.         t1->trktype = t2->trktype = 0;
  839.         t1->audioch = t2->audioch = 0;
  840.         t1->adr = t2->adr = 0;
  841.         t1->trkno = t2->trkno = i + 1;
  842.         t1->abs_addr.logical = bswap32(cdsim_stat.trk[i].addr);
  843.         blktomsf(
  844.             cdsim_stat.trk[i].addr,
  845.             &t2->abs_addr.msf.min,
  846.             &t2->abs_addr.msf.sec,
  847.             &t2->abs_addr.msf.frame,
  848.             FRAME_PER_SEC << 1
  849.         );
  850.  
  851.         t1 = (toc_trk_descr_t *)
  852.             ((byte_t *)(void *) t1 + sizeof(toc_trk_descr_t));
  853.         t2 = (toc_trk_descr_t *)
  854.             ((byte_t *)(void *) t2 + sizeof(toc_trk_descr_t));
  855.     }
  856.  
  857.     /* Lead-out track */
  858.     t1->preemph = t2->preemph = 0;
  859.     t1->copyallow = t2->copyallow = 0;
  860.     t1->trktype = t2->trktype = 0;
  861.     t1->audioch = t2->audioch = 0;
  862.     t1->adr = t2->adr = 0;
  863.     t1->trkno = t2->trkno = LEAD_OUT_TRACK;
  864.     t1->abs_addr.logical = bswap32(cdsim_stat.trk[i].addr);
  865.     blktomsf(
  866.         cdsim_stat.trk[i].addr,
  867.         &t2->abs_addr.msf.min,
  868.         &t2->abs_addr.msf.sec,
  869.         &t2->abs_addr.msf.frame,
  870.         FRAME_PER_SEC << 1
  871.     );
  872. }
  873.  
  874.  
  875. /*
  876.  * cdsim_main
  877.  *    The CD simulator main function
  878.  *
  879.  * Args:
  880.  *    Nothing.
  881.  *
  882.  * Return:
  883.  *    Nothing.
  884.  */
  885. void
  886. cdsim_main(void)
  887. {
  888.     int        i,
  889.             j;
  890.     simpkt_t    spkt,
  891.             rpkt;
  892.  
  893.     fprintf(errfp, "CD-ROM simulator version %s (pid=%d) starting...\n",
  894.         CDSIM_VERS, getpid());
  895.  
  896.     /* Install signal handlers */
  897.     signal(SIGINT, cdsim_sig);
  898.     signal(SIGTERM, cdsim_sig);
  899.     signal(SIGHUP, cdsim_sig);
  900.  
  901.     /* Initialize CD-ROM simulator */
  902.     cdsim_init();
  903.  
  904.     /* Main simulation service loop */
  905.     for (;;) {
  906.         /* Get SCSI request */
  907.         if (!cdsim_getpkt("cdsim", cdsim_sfd[0], &rpkt))
  908.             continue;
  909.  
  910.         time(&cdsim_now);
  911.         /* Update status */
  912.         switch (cdsim_stat.status) {
  913.         case CDSIM_PLAYING:
  914.             cdsim_elapsed = cdsim_now - cdsim_start_time -
  915.                 cdsim_pause_elapsed - cdsim_prev_pause;
  916.  
  917.             cdsim_stat.absaddr = cdsim_elapsed * FRAME_PER_SEC +
  918.                 cdsim_stat.startaddr;
  919.  
  920.             cdsim_stat.trkno = 0;
  921.             for (i = 0; i < (int) cdsim_stat.ntrks; i++) {
  922.                 if (cdsim_stat.trk[i].addr > cdsim_stat.absaddr)
  923.                     break;
  924.                 cdsim_stat.trkno++;
  925.             }
  926.  
  927.             cdsim_stat.idxno = 0;
  928.             for (j = 0; j < (int) cdsim_stat.trk[i-1].nidxs; j++) {
  929.                 if (cdsim_stat.trk[i-1].iaddr[j] >
  930.                     cdsim_stat.absaddr)
  931.                     break;
  932.                 cdsim_stat.idxno++;
  933.             }
  934.  
  935.             cdsim_stat.reladdr = cdsim_stat.absaddr -
  936.                 cdsim_stat.trk[i-1].addr;
  937.  
  938.             if (cdsim_stat.absaddr > cdsim_stat.endaddr) {
  939.                 cdsim_stat.status = CDSIM_STOPPED;
  940.                 cdsim_elapsed = 0;
  941.                 cdsim_start_time = 0;
  942.                 cdsim_pause_time = 0;
  943.                 cdsim_prev_pause = 0;
  944.                 cdsim_pause_elapsed = 0;
  945.             }
  946.             break;
  947.  
  948.         case CDSIM_PAUSED:
  949.             cdsim_pause_elapsed = cdsim_now - cdsim_pause_time;
  950.             break;
  951.         }
  952.  
  953.         /* Process SCSI request */
  954.         cdsim_svccmd(&rpkt, &spkt);
  955.     }
  956. }
  957.  
  958. #endif    /* DEMO_ONLY */
  959.  
  960.